package com.ruoyi.system.service.impl;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.common.EsIndex;
import com.ruoyi.system.domain.PoPublicOpinion;
import com.ruoyi.system.domain.PublicOpinionEvents;
import com.ruoyi.system.domain.PublicOpinionTopic;
import com.ruoyi.system.domain.vo.NameListValue;
import com.ruoyi.system.domain.vo.NameValue;
import com.ruoyi.system.service.ElasticsearchBasicService;
import com.ruoyi.system.service.ElasticsearchQueryBuilderService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ElasticsearchBasicServiceImpl implements ElasticsearchBasicService {

    @Resource(name = "restHighLevelClient")
    RestHighLevelClient restHighLevelClient;
    @Autowired
    ElasticsearchQueryBuilderService elasticsearchQueryBuilderService;
    @Autowired
    private EsUtil esUtil;
    private static RestHighLevelClient client;

    /**
     * @PostContruct是spring框架的注解 spring容器初始化的时候执行该方法
     */
    @PostConstruct
    public void init() {
        client = this.restHighLevelClient;
    }

    /**
     * 批量修改舆情的情感属性
     *
     * @param opinions
     * @return
     */
    @Override
    public int batchUpdateOpinionIndex(List<PoPublicOpinion> opinions) throws IOException {
        // 构建批量请求
        BulkRequest bulkRequest = new BulkRequest();
        for (PoPublicOpinion opinion : opinions) {
            UpdateRequest updateRequest = new UpdateRequest(EsIndex.OPINION, opinion.getId());
            XContentBuilder builder = XContentFactory.jsonBuilder();
            if (opinion.getIspositive() == 1) {
                builder.startObject()
                        .field("ispositive", 1)
                        .field("isneutral", 0)
                        .field("isnegative", 0)
                        .endObject();
            } else if (opinion.getIsneutral() == 1) {
                builder.startObject()
                        .field("ispositive", 0)
                        .field("isneutral", 1)
                        .field("isnegative", 0)
                        .endObject();
            } else if (opinion.getIsnegative() == 1) {
                builder.startObject()
                        .field("ispositive", 0)
                        .field("isneutral", 0)
                        .field("isnegative", 1)
                        .endObject();
            }
            updateRequest.doc(builder);
            bulkRequest.add(updateRequest);
        }

        // 执行批量操作
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        // 输出响应结果
        System.out.println("更新情感属性：" + bulkResponse);

        return 1;
    }

    @Override
    public int updateOpinionIndex(PoPublicOpinion opinion) throws IOException {
        // 构建批量请求
        BulkRequest bulkRequest = new BulkRequest();

        UpdateRequest updateRequest = new UpdateRequest(EsIndex.OPINION, opinion.getId());
        XContentBuilder builder = XContentFactory.jsonBuilder();
        if (opinion.getIspositive() == 1) {
            builder.startObject()
                    .field("ispositive", 1)
                    .field("isneutral", 0)
                    .field("isnegative", 0)
                    .endObject();
        } else if (opinion.getIsneutral() == 1) {
            builder.startObject()
                    .field("ispositive", 0)
                    .field("isneutral", 1)
                    .field("isnegative", 0)
                    .endObject();
        } else if (opinion.getIsnegative() == 1) {
            builder.startObject()
                    .field("ispositive", 0)
                    .field("isneutral", 0)
                    .field("isnegative", 1)
                    .endObject();
        }
        updateRequest.doc(builder);
        bulkRequest.add(updateRequest);

        // 执行批量操作
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        // 输出响应结果
        System.out.println("更新情感属性：" + bulkResponse);

        return 1;
    }

    @Override
    public Integer getTodayAlertCount(List<String> ids) {
        //构建查询语句
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Date currentDate = DateUtils.getCurrentDate();
        boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilderStartTime(boolQueryBuilder, currentDate);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.postFilter(QueryBuilders.termsQuery("id", ids));
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        return search(searchSourceBuilder);

    }

    @Override
    public Integer getTodayNegativeCount(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        //负面
        boolQueryBuilder.must(QueryBuilders.termQuery("isnegative", 1));
        Date startTime = DateUtils.getCurrentDate();
        Date endTime = DateUtils.getCurrentTime();
        //今日
        boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(boolQueryBuilder, startTime, endTime);
        searchSourceBuilder.trackTotalHits(true);
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        return search(searchSourceBuilder);
    }

    @Override
    public Integer getTodayPublicOpinionCount(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        Date startTime = DateUtils.getCurrentDate();
        Date endTime = DateUtils.getCurrentTime();
        //今日
        boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(boolQueryBuilder, startTime, endTime);
        searchSourceBuilder.trackTotalHits(true);
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        return search(searchSourceBuilder);
    }

    @Override
    public Integer getPastSevenDaysPublicOpinionCount(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        Date startTime = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-6));
        Date endTime = DateUtils.getCurrentTime();
        //近七日
        boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(boolQueryBuilder, startTime, endTime);
        searchSourceBuilder.trackTotalHits(true);
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        return search(searchSourceBuilder);
    }

    @Override
    public List<NameListValue> negativeInformationHeatMap(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        Date startTime = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-6));
        Date endTime = DateUtils.getCurrentTime();
        //近七日
        boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(boolQueryBuilder, startTime, endTime);
        //负面
        boolQueryBuilder.must(QueryBuilders.termQuery("isnegative", 1));
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        try {
            return esUtil.getCountGroupByPublishDateAndPublishTime(searchSourceBuilder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 获取正负面信息趋势图
     *
     * @param topics
     * @param events
     * @return
     */
    @Override
    public List<NameListValue> getSentimentByPublishTimeByTenantCode(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        searchSourceBuilder.query(boolQueryBuilder);
        return esUtil.getCountGroupByPublishDateSentiment(searchSourceBuilder);
    }


    /**
     * 舆情数量按省分组
     *
     * @param topics
     * @param events
     * @return
     */
    @Override
    public List<NameValue> getPublicOpinionCountGroupByProvinceOfTenantCode(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        searchSourceBuilder.query(boolQueryBuilder);
        return esUtil.getCountGroupByProvince(searchSourceBuilder);
    }

    @Override
    public List<NameValue> getHotWords(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        searchSourceBuilder.query(boolQueryBuilder);
        return esUtil.getCountGroupByKeywords(searchSourceBuilder, 100);
    }

    @Override
    public List<NameValue> getMediaActivity(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        searchSourceBuilder.query(boolQueryBuilder);
        return esUtil.getCountGroupByMediaName(searchSourceBuilder);
    }

    @Override
    public List<NameValue> getOpinionLeaders(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        searchSourceBuilder.query(boolQueryBuilder);
        return esUtil.getCountGroupByAuthor(searchSourceBuilder);
    }

    @Override
    public List<PoPublicOpinion> getNegativeListOfTenantCode(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events, int count) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        //负面
        boolQueryBuilder.must(QueryBuilders.termQuery("isnegative", 1));
        boolQueryBuilder.minimumShouldMatch(1);
        searchSourceBuilder.query(boolQueryBuilder);
        List<PoPublicOpinion> list = null;
        try {
            list = esUtil.search(searchSourceBuilder, PoPublicOpinion.class, count!=0?count:10);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    @Override
    public List<PoPublicOpinion> getHotListOfTenantCode(List<PublicOpinionTopic> topics, List<PublicOpinionEvents> events, int count) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(events, topics);
        //排序
        List<SortBuilder<?>> sorts = new ArrayList<>();
        SortBuilder sortBuilder = SortBuilders.fieldSort("hot").order(SortOrder.DESC);
        sorts.add(sortBuilder);
        searchSourceBuilder.sort(sorts);
        searchSourceBuilder.query(boolQueryBuilder);
        List<PoPublicOpinion> list = null;
        try {
            list = esUtil.search(searchSourceBuilder, PoPublicOpinion.class, count!=0?count:10);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 查询数量
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public Integer search(SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = searchResponse.getHits();
            return (int) hits.getTotalHits().value;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}
